package cn.xzqwjw.taskmanager.security;

import java.util.Collection;
import java.util.Collections;

import lombok.Getter;
import org.springframework.security.authentication.AbstractAuthenticationToken;
import org.springframework.security.core.GrantedAuthority;

/*
 * 用户登录的时候，AuthUsernamePasswordFilter 拦截器会拦截登录表单
 * 将表单里的用户名密码封装成一个 UsernamePasswordAuthenticationToken
 * 然后将这个 token 传给 AuthenticationManager ，这个Manager会调用 Provider 执行具体的验证
 * 因此类似的，我们自定义的 JwtFilter 拦截器也要拦截每个请求，获取 Header 里的 jwt
 * 然后将这个jwt封装成一个 JwtAuthenticationToken
 * 然后将这个 token 传给 AuthenticationManager
 * 这个 Manager 会调用 我们自定义的 AuthJwtProvider 执行具体的验证
 * UsernamePasswordAuthenticationToken 里封装了用户名密码权限
 * 我们的 JwtAuthenticationToken 里封装了jwt，但是都是继承于 AbstractAuthenticationToken
 */

/**
 * @author rush
 */
public class TokenJwt extends AbstractAuthenticationToken {

  private static final long serialVersionUID = 1L;

  private final Object principal;
  private Object credentials;

  /**
   * 定义JWT令牌
   */
  @Getter
  private final String jwtString;

  /**
   * 只有一个参数的构造函数是用在jwt拦截器拦截请求的时候
   * 此时从 Header 里只能得到 jwt
   * 因此只需要一个参数，其他都是空值
   */
  public TokenJwt(String jwtString) {
    /*
     * Collections.EMPTY_LIST返回的是一个空的List。为什么需要空的List呢？
     * 有时候我们在函数中需要返回一个List，但是这个List是空的，如果我们直接返回null的话，
     * 调用者还需要进行null的判断，所以一般建议返回一个空的List。
     * Collections.EMPTY_LIST返回的这个空的List是不能进行添加元素这类操作的。
     * 这时候你有可能会说，我直接返回一个new ArrayList()呗，
     * 但是new ArrayList()在初始化时会占用一定的资源，
     * 所以在这种场景下，还是建议返回Collections.EMPTY_LIST。
     * Collections.emptyList() 返回的也是一个空的List，
     * 它与Collections.EMPTY_LIST的唯一区别是，
     * Collections.emptyList() 支持泛型，
     * 所以在需要泛型的时候，可以使用Collections.emptyList()
     */
    super(Collections.emptyList());
    this.principal = "";
    this.credentials = "";
    this.jwtString = jwtString;
    this.setAuthenticated(false);
  }

  /** 这个构造函数用在 provider 验证jwt后返回值给 filter 时，此时应构造比较完整的 token */
  public TokenJwt(Object principal,
                  String jwtString,
                  Collection<? extends GrantedAuthority> authorities) {
    super(authorities);
    this.principal = principal;
    this.jwtString = jwtString;
    super.setAuthenticated(true);
  }

  @Override
  public Object getPrincipal() {
    return this.principal;
  }

  @Override
  public Object getCredentials() {
    return this.credentials;
  }

}
